﻿using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.ServiceModel.Syndication;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System;
using Robert.BlogUpdater.Properties;

namespace Robert.BlogUpdater.Classes
{
    class RSSFeed: INotifyPropertyChanged
    {
        private string feedTitle;
        private string feedURL;
        
        public string FeedTitle
        {
            set { feedTitle = value; OnPropertyChanged("FeedTitle"); }
            get { return feedTitle; }
        }

        public string FeedURL
        {
            set { feedURL = value; OnPropertyChanged("FeedURL"); }
            get { return feedURL; }
        }

        public override string ToString()
        {
            return FeedTitle;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string info)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(info));
            }
        }
    }

    class RSSFeedList : ObservableCollection<RSSFeed>
    {
        /// <summary>
        /// Loads your RSSFeedList from the AppSeetings.
        /// </summary>
        /// <returns>RSSFeedList</returns>
        public static RSSFeedList Load()
        {
            RSSFeedList feedList = new RSSFeedList();
                                    
            for (int i=0; i < (int)Settings.Default.FeedNumbers; i++)
            {
                RSSFeed feed = new RSSFeed();
                feed.FeedTitle = Settings.Default.FeedNames[i];
                feed.FeedURL = Settings.Default.FeedURLs[i];
                feedList.Add(feed);
            }

            return feedList;
        }
        /// <summary>
        /// Finds the given RSSFeed in the given RSSFeedList. Returns a RSSFeed.
        /// </summary>
        /// <param name="feed">The RSSFeed to search.</param>
        /// <param name="feedList">The RSSFeedList to search in.</param>
        /// <returns>RSSFeed</returns>
        public static RSSFeed FindFeed(RSSFeed feed, RSSFeedList feedList)
        {
            RSSFeed feedLocated = null;

            foreach (RSSFeed feedLocator in feedList)
            {
                if (feedLocator == feed)
                {
                    feedLocated = feedLocator;
                    break;
                }
            }
            return feedLocated;
        }
        /// <summary>
        /// Finds the given feedTitle in the given RSSFeedlist. Returns a RSSFeed.
        /// </summary>
        /// <param name="feedTitle">The Feed with the feedTitle.</param>
        /// <param name="feedList">The RSSFeedList to search in.</param>
        /// <returns>RSSFeed</returns>
        public static RSSFeed FindFeed(string feedTitle, RSSFeedList feedList)
        {
            RSSFeed feedLocated = null;

            foreach (RSSFeed feedLocator in feedList)
            {
                if (feedLocator.FeedTitle == feedTitle)
                {
                    feedLocated = feedLocator;
                    break;
                }
            }
            return feedLocated;
        }
        /// <summary>
        /// Save the given RSSFeedList into the AppSettings.
        /// </summary>
        /// <param name="feeds">The RSSFeedList to save.</param>
        public void Save(RSSFeedList feeds)
        {
            //Always clear before saving.
            //Found an bug when removing a feed that causes index screw-ups.
            Settings.Default.FeedNames.Clear();
            Settings.Default.FeedNumbers = 0;
            Settings.Default.FeedURLs.Clear();
            foreach (RSSFeed feed in feeds)
            {
                if (!Settings.Default.FeedNames.Contains(feed.FeedTitle))
                {
                    Settings.Default.FeedNames.Add(feed.FeedTitle);
                    Settings.Default.FeedURLs.Add(feed.FeedURL);
                }
            }
            Settings.Default.FeedNumbers = feeds.Count;
            Settings.Default.Save();
        }
    }

    class RSSFeedPost
    {
        private string postSummary;
        private Uri postURL;
        private DateTimeOffset postDate;
        private string postTitle;

        public string PostSummary
        {
            set { postSummary = value; }
            get { return postSummary; }
        }

        public Uri PostURL
        {
            set { postURL = value; }
            get { return postURL; }
        }

        public string PostDate
        {
            set { postDate = DateTimeOffset.Parse(value); }
            get { return string.Format("{0} {1}/{2}/{3} {4}:{5}", postDate.DayOfWeek, postDate.Day, postDate.Month, postDate.Year, postDate.TimeOfDay.Hours, postDate.TimeOfDay.Minutes); }
        }

        public string PostTitle
        {
            set { postTitle = value; }
            get { return postTitle; }
        }
    }

    class RSSFeedPostList : ObservableCollection<RSSFeedPost>
    {
        /// <summary>
        /// Loads the feed posts from a given SyndicationFeed.
        /// </summary>
        /// <param name="synFeed">The SyndicationFeed to load the posts from.</param>
        /// <returns>RSSFeedPostList</returns>
        public static RSSFeedPostList Load(SyndicationFeed synFeed)
        {
            RSSFeedPostList postList = new RSSFeedPostList();

            foreach (SyndicationItem item in synFeed.Items)
            {
                RSSFeedPost post = new RSSFeedPost();
                post.PostSummary = HTMLMethods.Shrink(HTMLMethods.StripHTML(item.Summary.Text));
                post.PostURL = item.Links[0].Uri;
                post.PostDate = item.PublishDate.ToString();
                post.PostTitle = item.Title.Text;
                postList.Add(post);
            }

            return postList;
        }
    }

    class HTMLMethods
    {
        /// <summary>
        /// Removes the basic HTML tags from the given string.
        /// </summary>
        /// <param name="text">String from where you want to remove the HTML tags.</param>
        /// <returns>string</returns>
        public static string StripHTML(string text)
        {
            text = Regex.Replace(text, @"<(.|\n)*?>", String.Empty);
            text = text.Replace("&gt;", ">");
            text = text.Replace("&lt;", "<");
            text = text.Replace("&nbsp;", " ");
            text = text.Replace("&#8217;", "'");
            text = text.Replace("&#8230;", "...");
            text = text.Replace("\t", string.Empty);
            return text;
        }
        /// <summary>
        /// Shrinks the given string to a more friendly string for the app.
        /// </summary>
        /// <param name="text">String to shrink.</param>
        /// <returns>string</returns>
        public static string Shrink(string text)
        {
            while (text.Contains("\n"))
                    text = text.Replace("\n", string.Empty);
            if (text.Length > 200)
            {
                text = text.Remove(200);
                text = text.Insert(text.Length, "...");
            }
            else
                if (text.Length == 0)
                    text = "Nothing to show. For now.\n\nPost summary is blank.";
                else
                {
                    text = text.Remove(text.Length - 5);
                    text = text.Insert(text.Length, "...");
                }
            return text;
        }
    }
}
